﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Wolfpack.Periscope.Core.Extensions;
using Wolfpack.Periscope.Core.Infrastructure;
using Wolfpack.Periscope.Core.Interfaces;
using Wolfpack.Periscope.Core.Interfaces.Entities;
using Wolfpack.Periscope.Core.Interfaces.Events;

namespace Wolfpack.Periscope.Core
{    
    public partial class Dashboard : IDashboard
    {
        private readonly TinySubscriptionManager _subscriptionManager;
        private readonly IDashboardInfrastructure _infrastructure;
        private readonly IDashboardConfigurationRepository _repository;

        private readonly IPanelRenderer _panelRenderer;        

        public Dashboard(IDashboardInfrastructure infrastructure, 
            IDashboardConfigurationRepository repository,
            IPanelRenderer panelRenderer)
        {
            _infrastructure = infrastructure;
            _repository = repository;
            _panelRenderer = panelRenderer;

            _subscriptionManager = _infrastructure.MessageBus.CreateSubscriptionManager();
        }

        public IDashboardInfrastructure Infrastructure { get { return _infrastructure; }}
        public DashboardConfiguration Configuration { get { return _repository.Load(); }}

        public void Start()
        {
            _subscriptionManager.AddHandler<PanelRotateRequestEvent>(HandlePanelRotateRequestEvent)
                .AddHandler<PanelLayoutChangeRequestEvent>(HandlePanelLayoutChangedEvent)
                .AddHandler<AddWidgetToPanelCommand>(HandleAddWidgetToPanelEvent)
                .AddHandler<WidgetResizeCommand>(HandleWidgetResizeRequestEvent)
                .AddHandler<AddPanelToDashboardCommand>(HandleAddPanelToDashboardEvent);

            Parallel.ForEach(_infrastructure.Plugins, plugin =>
            {
                Infrastructure.Logger.LogDebug("Initialising plugin: {0}", plugin.GetType().BuildTypeName());
                plugin.Initialise();
            });

            foreach (var plugin in _infrastructure.Plugins)
            {
                Infrastructure.Logger.LogDebug("Starting plugin: {0}", plugin.GetType().BuildTypeName());
                plugin.Start();                
            }                      
        }

        public RenderedPanel RenderPanel(string panelName)
        {
            var config = _repository.Load();
            var panel = config.Panels.SingleOrDefault(x => x.Name.Equals(panelName,
                StringComparison.OrdinalIgnoreCase));

            if (panel == null)
                throw new InvalidOperationException(string.Format("No panel exists with name '{0}'", panelName));

            return _panelRenderer.Render(panel);
        }

        public void Dispose()
        {
            _subscriptionManager.Dispose();
            _infrastructure.Dispose();
        }

        private void ApplyLayoutToConfig(ILayoutChangeRequest layout, out IDashboardPanel panelUpdated)
        {
            var config = _repository.Load();
            var panel = config.Panels.FindOrFail(layout.PanelId);

            if (!panel.Version.Equals(layout.PanelVersion))
                throw new InvalidOperationException(string.Format("Panel layout is stale, unable to update layout!"));

            foreach (var widgetLayout in layout.Layout)
            {
                WidgetInstance widgetInstance;

                if (!panel.Widgets.Find(widgetLayout.Id, out widgetInstance))
                {
                    _infrastructure.Logger.LogWarning("Widget '{0}' does not exist in the configuration!",
                        widgetLayout.Id);
                    continue;
                }

                widgetInstance.UpdateLayout(widgetLayout);
            }

            _repository.Save(config);
            panelUpdated = panel;
        }
    }
}